package com.budwk.app.sqfw.component;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.JSONObject;
import com.budwk.app.common.config.AppException;
import com.budwk.app.sqfw.enums.PushChannelEnum;
import com.budwk.app.sqfw.models.SqfwPushMsgLog;
import com.budwk.app.sqfw.models.Sqfw_servicerecord;
import com.budwk.app.sqfw.services.*;
import com.budwk.app.sqfw.vo.pushmsg.PushMsgConfigVo;
import com.budwk.app.sqfw.vo.pushmsg.PushMsgContentVo;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.starter.common.result.Result;
import com.budwk.starter.email.EmailSendServer;
import com.budwk.starter.security.utils.SecurityUtil;
import com.huawei.push.android.BadgeNotification;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.async.Async;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@IocBean
public class PushMsgComponent {

    @Inject
    private HuaweiInterfaceService huaweiInterfaceService;
    @Inject
    private XiaomiInterfaceService xiaomiInterfaceService;
    @Inject
    private VivoInterfaceService vivoInterfaceService;
    @Inject
    private OppoInterfaceService oppoInterfaceService;
    @Inject
    private SqfwPushMsgLogService sqfwPushMsgLogService;
    @Inject
    private EmailSendServer emailSendServer;

    @Inject("taskQueryExecutor")
    private ThreadPoolExecutor taskQueryExecutor;

    public static final String PUSH_CHANNEL = "pushChannel";

    public static final String PUSH_TOKEN = "pushToken";

    // 消息发送方式
    public static final String MSG_CC = "msg_cc";

    public static final String MSG_ASSIGN = "msg_assign";

    public static final String MSG_TYPE_SYSTEM = "系统消息";

    public static final String MSG_TYPE_ERPSON = "人工消息";


    /**
     * 发送信息失败邮件接收者账号信息
     */
    private static final List<String> PUSH_EMAIL_RECEIVE_ACCOUNT = new ArrayList<>(){{
        add("xiaozy000@qq.com");
        add("850715177@qq.com");
    }};

    /**
     * 重试
     */
    @Async
    public void retry(PushMsgConfigVo c, Sys_user receiveUser, Sys_user pushUser, PushMsgContentVo msgVo, String msgType, String pushBatchNo) {
        log.info("start push msg retry sqfwId: {}", c.getSqfwId());
        boolean retrySuccess = false; // 是否重试成功 默认失败
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                log.error("sleep error: ", e);
            }
            boolean isSuccess = sendMsg(c, msgVo.getContent());
            if (isSuccess) {
                retrySuccess = true;
                break;
            }
        }
        // 如果重试失败
        if (!retrySuccess) {
            log.info("push msg retry fail retrySuccess: {}", retrySuccess);
            // 1 插入数据库
            insertFailMsgLog(c, receiveUser, pushUser, msgVo, msgType, pushBatchNo);
            // 2 发送邮件信息
            sendEmail(msgVo.getContent(), c.getPushChannel());
            return;
        }
        insertSuccessMsgLog(c, receiveUser, pushUser, msgVo, msgType, pushBatchNo);
    }

    private void sendEmail(String content, String pushChannel) {
        // 发送内容
        String pushContent = String.format("%s%s%s%s", "你有一条信息推送失败，推送渠道为：", pushChannel, "，请尽快处理，信息内容为：", content);
        // 异步执行发送邮件
        CompletableFuture[] cf = PUSH_EMAIL_RECEIVE_ACCOUNT.stream().map(data -> CompletableFuture.runAsync(() ->
                emailSendServer.sendMsg("系统管理员", "祥云小助", data, pushContent), taskQueryExecutor)
                .thenApply(r -> r)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(cf).join();
        log.info("sendEmail email end...........");
    }


    public boolean sendMsg(PushMsgConfigVo c, String msgContent) {
        try {
            String pushChannel = c.getPushChannel();
            String pushToken = c.getPushToken();
            if (PushChannelEnum.HUAWEI.getName().equals(pushChannel)) {
                BadgeNotification b = null;
                if(StringUtils.isNotEmpty(c.getBadgeNotification())) {
                    b = JSONObject.parseObject(c.getBadgeNotification(), BadgeNotification.class);
                }
                huaweiInterfaceService.sendhuaweinotifymessage(pushToken, msgContent, c.getSqfwId(), c.getAction(), b);
                return true;
            }
            // 2.2 小米信息发送
            if (PushChannelEnum.XIAOMI.getName().equals(pushChannel)) {
                xiaomiInterfaceService.sendXiaomiMessage(pushToken, msgContent, c.getAction(), c.getSqfwId());
                return true;
            }
            // 2.3 vivo信息发送
            if (PushChannelEnum.VIVO.getName().equals(pushChannel)) {
                vivoInterfaceService.pushVivoMessage(msgContent, c.getAction(), pushToken, c.getSqfwId());
                return true;
            }
            // 2.4 oppo信息发送
            if (PushChannelEnum.OPPO.getName().equals(pushChannel)) {
                oppoInterfaceService.pushOppoMessage(msgContent, c.getAction(), pushToken, c.getSqfwId());
            }
            return true;
        } catch (Exception e) {
            log.error("sendMsg error: ", e);
            return false;
        }
    }

    /**
     * 校验是否满足发送条件
     * @return 满足或者不满足
     */
    public boolean isPushMsg(PushMsgConfigVo c) {
        if (StringUtils.isEmpty(c.getPushToken())) {
            return false;
        }
        if (StringUtils.isEmpty(c.getPushChannel())) {
            return false;
        }
        Optional<PushChannelEnum> optional = PushChannelEnum.getPushChannelEnum(c.getPushChannel());
        if (optional.isEmpty()) {
            return false;
        }
        return true;
    }

    /**
     * 获取发送内容体
     * @param action action值
     */
    public PushMsgContentVo getPushContent(String action, Sys_user copyUser, Sqfw_servicerecord serviceRecord) {
        String msgContent = StringUtils.EMPTY;
        if (MSG_CC.equals(action)) {
            msgContent = String.format("%s%s%s", "您有一条来自", copyUser.getUsername(), "的抄送消息");
        }
        if (MSG_ASSIGN.equals(action)) {
            msgContent = String.format("%s%s%s%s", "【", serviceRecord.getCustomer_need(), "】 任务来源:", serviceRecord.getCustomer_name());
        }
        log.info("push message content value: {}", msgContent);

        PushMsgContentVo msgVo = new PushMsgContentVo();
        msgVo.setContent(msgContent)
                .setTitle("祥云小助")
                .setPushDate(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN))
                .setPusherText("来自" + SecurityUtil.getUserUsername() + "的信息");
        return msgVo;
    }

    public static PushMsgConfigVo buildPushMsgConfigVo(Map<String, String> mapToken, String sqfwId, String action, String b) {
        PushMsgConfigVo c = new PushMsgConfigVo();
        c.setPushChannel(mapToken.get(PUSH_CHANNEL).toString())
                .setPushToken(mapToken.get(PUSH_TOKEN).toString())
                .setSqfwId(sqfwId)
                .setAction(action)
                .setBadgeNotification(b);
        return c;
    }

    /**
     * 插入成功的消息日志信息
     */
    public void insertSuccessMsgLog(PushMsgConfigVo c, Sys_user receiveUser, Sys_user pushUser,
                                  PushMsgContentVo msgVo, String msgType, String pushBatchNo) {
        SqfwPushMsgLog sqfwPushMsgLog = new SqfwPushMsgLog();
        sqfwPushMsgLog.setPushMsgConfig(JSONObject.toJSONString(c))
                .setPushUserName(pushUser.getUsername())
                .setPushUserId(pushUser.getId())
                .setReceiveUserName(receiveUser.getUsername())
                .setReceiveUserPhone(receiveUser.getMobile())
                .setReceiveId(receiveUser.getId())
                .setContextData(JSONObject.toJSONString(msgVo))
                .setMsgType(msgType)
                .setPushBatchNo(pushBatchNo)
                .setIsSuccess(true)
                .setRead(false)
                .setRemark("发送成功");
        SqfwPushMsgLog msgLog = sqfwPushMsgLogService.fetch(c.getSqfwId());
        if (msgLog == null) {
            sqfwPushMsgLog.setId(c.getSqfwId());
        }
        sqfwPushMsgLogService.insert(sqfwPushMsgLog);
        log.info("insertFailMsgLog info param: {}", JSONObject.toJSONString(sqfwPushMsgLog));
    }

    /**
     * 插入失败的消息日志信息
     */
    public void insertFailMsgLog(PushMsgConfigVo c, Sys_user receiveUser, Sys_user pushUser, PushMsgContentVo msgVo, String msgType, String pushBatchNo) {
        SqfwPushMsgLog sqfwPushMsgLog = new SqfwPushMsgLog();
        sqfwPushMsgLog.setPushMsgConfig(JSONObject.toJSONString(c))
                .setPushUserName(pushUser.getUsername())
                .setPushUserId(pushUser.getId())
                .setReceiveUserName(receiveUser.getUsername())
                .setReceiveUserPhone(receiveUser.getMobile())
                .setReceiveId(receiveUser.getId())
                .setContextData(JSONObject.toJSONString(msgVo))
                .setIsSuccess(false)
                .setMsgType(msgType)
                .setPushBatchNo(pushBatchNo)
                .setRead(false)
                .setRemark("发送失败");
        SqfwPushMsgLog msgLog = sqfwPushMsgLogService.fetch(c.getSqfwId());
        if (msgLog == null) {
            sqfwPushMsgLog.setId(c.getSqfwId());
        }
        sqfwPushMsgLogService.insert(sqfwPushMsgLog);
        log.info("insertFailMsgLog info param: {}", JSONObject.toJSONString(sqfwPushMsgLog));
    }

    public Result<?> failMsgRetry(String msgId) {
        SqfwPushMsgLog sqfwPushMsgLog = sqfwPushMsgLogService.fetch(msgId);
        if (sqfwPushMsgLog == null) {
            throw new AppException("重试失败：查询不到对应的失败消息");
        }
        if (sqfwPushMsgLog.getIsSuccess()) {
            throw new AppException("该消息已经发送成功，无需重试");
        }
        // 发送消息
        PushMsgConfigVo c = JSONObject.parseObject(sqfwPushMsgLog.getPushMsgConfig(), PushMsgConfigVo.class);
        PushMsgContentVo m = JSONObject.parseObject(sqfwPushMsgLog.getContextData(), PushMsgContentVo.class);
        boolean isSuccess = sendMsg(c, m.getContent());
        if (!isSuccess) {
            throw new AppException("重试失败，请联系系统管理员");
        }
        sqfwPushMsgLog.setIsSuccess(true).setUpdatedAt(System.currentTimeMillis());
        sqfwPushMsgLogService.update(sqfwPushMsgLog);
        return Result.success();
    }
}
